// mode7.c
#include <math.h>

void draw_mode7(	int ** screen, const int screen_size_x, int screen_size_y,
					const int ** tilemap, const int tilemap_size_x, const int tilemap_size_y,
					const int ** tileset, const int tileset_size_x, const int tileset_size_y,
					const int tile_size_x, const int tile_size_y, const int edgetile,
					const double angle, const float cam_x, const float cam_y, const int space_z, const int horizon,
					const double scale_x, const double scale_y,
					const int anim_frame, const int fog_distace, const int fog_color) {
	// Aktuelle Position auf dem Bildschirmausschnitt
	int screen_x, screen_y;

	// Offset des aktuellen Tiles in dem Tileset und dessen Wert
	int offset_x, offset_y, tile;

	// Entfernung und daraus resultierende skalierung der aktuellen Zeile
	double distance, horizontal_scale;

	// Damit wir nicht auf Bereiche ausserhalb des Tiles zugreifen
	int tile_mask_x = tile_size_x - 1;
	int tile_mask_y = tile_size_y - 1;

	// Pixelweise Veraenderung der Position in einer Zeile auf der Map
	double line_dx, line_dy;

	// Aktuelle Position auf der Map (Pixel)
	double space_x, space_y;
	
	// Die Farbe des aktuellen Pixels
	int pixel;

	// Intensitaet des Nebels
	/*int fog_intensity;
	int red_channel, blue_channel, green_channel;*/

	// Jede Bildschirmzeile durchgehen (virtueller Bereich)
	for (screen_y = 0; screen_y < screen_size_y; screen_y ++) {
		// Entfernung zur zu rendernden Zeile
		distance = (space_z / scale_y) / (screen_y + horizon);
		// Skalierung aus der Entfernung bestimmen
		horizontal_scale = distance * scale_x;

		// Abstaende zwischen den Pixeln der Map auf dem Bildschirm (perspektivisch)
		line_dx = -sin(angle) * horizontal_scale;
		line_dy = cos(angle) * horizontal_scale;

		// Startposition fuer die aktuelle Zeile bestimmen, Kamera
		// umkreist die uebergebene Position um 40px Entfernung
		/*space_x = (cam_x - cos(angle) * 40) + distance * cos(angle) - screen_size_x / 2 * line_dx;
		space_y = (cam_y - sin(angle) * 40) + distance * sin(angle) - screen_size_x / 2 * line_dy;*/
		// Startposition fuer die aktuelle Zeile bestimmen
		space_x = cam_x + distance * cos(angle) - (screen_size_x >> 1) * line_dx; // space_x = (cam_x - cos(angle) * 40) + di...
		space_y = cam_y + distance * sin(angle) - (screen_size_x >> 1) * line_dy; // space_y = (cam_y - sin(angle) * 40) + di...

		// Alle Punkte der aktuellen _Bildzeile_ (nicht Mapzeile) durchgehen
		for (screen_x = 0; screen_x < screen_size_x; screen_x ++) {
			// Offset des Tiles bestimmen
			offset_x = (((int)space_x) >> 3) - 1;	// (int)space_x / tile_size_x - 1;
			offset_y = (((int)space_y) >> 3) - 1;	// (int)space_y / tile_size_y - 1;
// 			offset_x = (int)space_x / tile_size_x - 1;
// 			offset_y = (int)space_y / tile_size_y - 1;
			// Pruefen ob sich das Tile ausserhalb des Mapbereichs befindet
			if((offset_x >= tilemap_size_x) | (offset_x < 0) | (offset_y >= tilemap_size_y) | (offset_y < 0))
				tile = edgetile;
			else {
				// Aktuelles Tile ermitteln
				//if(offset_x == (int)(cam_x / tile_size_x) && offset_y == (int)(cam_y / tile_size_y))
				//	tile = 0x00;
				//else
					tile	= tilemap[0][offset_y * tilemap_size_x + offset_x];
					//if(tile >= 0x08)
					//	tile += anim_frame;
				
			}
// 			tile = 0;

			// Farbe des Pixels bestimmen
			pixel = //tile;
				// Beginn der Tiledaten im Tileset bestimmen
				tileset[0][tile * tile_size_x * tile_size_y +
					((int)(space_y) & tile_mask_y) * tile_size_x + ((int)(space_x) & tile_mask_x)];
//				+ ((int)(space_y) & tile_mask_y) * tileset_size_x * tile_size_x + ((int)(space_x) & tile_mask_x)];
// 				tileset[0][((tile << 3) +  (tile / tileset_size_x) * (tile_size_x * tileset_size_x * (tile_size_y - 1)))
// 				+ ((int)(space_y) & tile_mask_y) * tileset_size_x * tile_size_x + ((int)(space_x) & tile_mask_x)];
			/*pixel =
				tileset[0][(tile * tile_size_x + (tile / tileset_size_x) * (tile_size_x * tileset_size_x * (tile_size_y - 1))) +
				((int)(space_y) & tile_mask_y) * tileset_size_x * tile_size_x + ((int)(space_x) & tile_mask_x)];*/
			
			// tileset[0][((tile << 3) + (tile / tileset_size_x) * (tile_size_x * tileset_size_x * (tile_size_y - 1)))];
			
			// Verrechnet den bestimmten Wert mit der Nebelfarbe, abhaengig von der Entfernung
			/*pixel = (((((pixel >> 16) * (fog_intensity+1)) >> 8) + (((fog_color >> 16) * (256-fog_intensity)) >> 8)) << 16) |
					(pixel & 0x00FFFF);*/
// 					((((((pixel & 0xFFFF) >> 8) * (fog_intensity+1)) >> 8) + ((fog_color * (256-fog_intensity)) >> 8)) << 8) |
// 					((((pixel & 0xFF) * (fog_intensity+1)) >> 8) + ((fog_color * (256-fog_intensity)) >> 8));
			/*if(fog_distace > 0) {
				red_channel		= pixel >> 16;
				green_channel	= (pixel & 0xFFFF) >> 8;
				blue_channel	= pixel & 0xFF;
				
				if(distance > fog_distace) {
					fog_intensity = distance - fog_distace;
					if(fog_intensity > 255)
						fog_intensity = 255;
				}
				
				red_channel		= (((fog_color >> 16) * (fog_intensity + 1)) >> 8) + ((red_channel * (256 - fog_intensity)) >> 8);
				green_channel	= ((((fog_color & 0xFFFF) >> 8) * (fog_intensity + 1)) >> 8) + ((green_channel * (256 - fog_intensity)) >> 8);
				blue_channel	= (((fog_color & 0xFF) * (fog_intensity + 1)) >> 8) + ((blue_channel * (256 - fog_intensity)) >> 8);
				pixel = (red_channel << 16) | (green_channel << 8) | blue_channel;
			}*/

			// Entsprechendes Zielpixel aus der Map auf den Bildschirmausschnitt zeichen
			screen[0][screen_y * screen_size_x + screen_x] = pixel;
			
			// Entspechende Pixelanzahl auf der Map weitergehen
			space_x += line_dx;
			space_y += line_dy;
		}
	}
	
/*	int obj_size = 16;
	int width, height;

	// 
	double obj_x = 300 - cam_x;
	double obj_y = 200 - cam_y;
	
	// 
	space_x = (obj_x * cos(angle)) + (obj_y * sin(angle));
	space_y = -(obj_x * sin(angle)) + (obj_y * cos(angle));
	
	// 
	screen_x = screen_size_x / 2 + (int)(((scale_x / space_x) * space_y));
	screen_y = (int)(((space_z * scale_y) / space_x)) - horizon;
	
	if(screen_x < 0 || screen_x > screen_size_x || screen_y < 0 || screen_y > screen_size_y)
		return;
// 	
	// 
// 	height = (int)(obj_size * (!!!!scale_y / space_x));
// 	width = (int)(obj_size * (scale_x / space_x));
// 	
// 	// draw the object
// 	stretch_sprite (bmp, obj, screen_x - width / 2, screen_y - height, width, height);

	int pixel_y;
	int pixel_x;
	height = obj_size;
	width = obj_size;
	for(pixel_y = 0; height > pixel_y; pixel_y ++) {
		for(pixel_x = 0; width > pixel_x; pixel_x ++) {
 			screen[0][screen_y * screen_size_x + screen_x + pixel_y * screen_size_x + pixel_x] = 0x000000;
		}
	}*/
}
